package com.woniu.microchargeserver.chargemag.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniu.microchargeserver.chargemag.other.projectserver.service.IProjectService;
import com.woniu.microchargeserver.chargemag.other.property.service.IPropertyService;
import com.woniu.microchargeserver.chargemag.service.IChargedItemsService;
import com.woniu.microchargeserver.chargemag.service.IRoomChargeService;
import com.woniu.microchargeserver.common.bean.dtobean.CustomerChargeTotalDto;
import com.woniu.microchargeserver.common.bean.dtobean.RoomChargeDto;
import com.woniu.microchargeserver.common.bean.dtobean.RoomChargeProDto;
import com.woniu.microchargeserver.common.mapper.RoomChargeMapper;
import com.woniu.microcommonsserver.entity.ChargedItemsInfoEntity;
import com.woniu.microcommonsserver.entity.OwnerInfoEntity;
import com.woniu.microcommonsserver.entity.RoomChargedItemsInfoEntity;
import com.woniu.microcommonsserver.entity.SpaceInfoEntity;
import com.woniu.microcommonsserver.param.ResponseMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;

import javax.annotation.Resource;
import java.util.*;

/**房间、收费项目 的中间表服务实现
 * @author: hejie
 * @date: 2021/1/25 9:43
 * @description:
 */
@Service
@Transactional(readOnly = true)
public class RoomChargeServiceImpl implements IRoomChargeService {

    @Resource
    private RoomChargeMapper roomChargeMapper;
    @Resource
    private IChargedItemsService chargedItemsService;
    //项目微服务
    @Resource
    private IProjectService projectServiceImpl;
    //物业微服务
    @Resource
    private IPropertyService propertyServiceImpl;



    /**查询该房间的  房间名字、业主、所有收费项目
     * 查询所有的 房间（就是房间的List）：List<SpaceInfoEntity>
     * 根据“build_info中的id”查询属于该build的所有building下的所有房间(如“水青花都小区-11号楼-5单元-8层-802”，即rank为4的SpaceInfoEntity)
     * 如3号楼
     * @author hejie
     * @param bId：build_info中的id
     * @param buildingId 楼栋的id
     * @param roomName 房间的名字（在前端传入的是 “3-5-1002”，impl处需要 把它转为“xxx小区-3号楼-5单元-10层-1002”）
     * @return
     */
    @Override
    public List<RoomChargeProDto> findRoomsByParams(Long bId,
                                                    Long buildingId,
                                                    String roomName,
                                                    String ownerName){
        //装最终的对象：
        List<RoomChargeProDto> roomChargeProDtoList=new ArrayList<>();

        //根据“楼栋id”，查询它的简称
        SpaceInfoEntity building=projectServiceImpl.findSpaceById(buildingId);
        String buildingAbbreviation=null;
        if (building!=null){
            buildingAbbreviation= building.getAbbreviation();
        }

        //房间名字处理：前端传来的是3-5-102，这里要转换为 3号楼-5单元-1层-102
      if (roomName!=null){
          String[] roomNameArr=roomName.split("-");
          if (roomNameArr.length==3){
              String completeRoomName=roomNameArr[0]+"号楼-"
                      +roomNameArr[1]+"单元-"
                      +roomNameArr[2].substring(0,roomNameArr[2].length()-2)+"层-"
                      +roomNameArr[2];
              roomName=completeRoomName;
          }
      }

        //查询某个build下面的所有房间 List<SpaceInfoEntity>
        List<SpaceInfoEntity> allRoom =projectServiceImpl.findRoomsByParams(
                bId,
                buildingId,
                buildingAbbreviation,
                roomName);

        for ( int i=0; i<allRoom.size(); i++) {
            SpaceInfoEntity spaceInfoEntity=allRoom.get(i);

            //获取room的全称：如 “水青花都小区-11号楼-5单元-8层-802”
            String fullname= spaceInfoEntity.getFullname();
            String[] names=  fullname.split("-");
            //下面的“-2”是“号楼”或“单元两个字的长度
            String houseName= names[1].substring(0,names[1].length()-2) +"-"
                    + names[2].substring(0,names[2].length()-2) +"-"
                    + names[4];
//            spaceInfoEntity.setAbbreviation( houseName );


            //查询房间 下的所有“收费项目”：根据房间的id，查询该房间下面所有的 “收费项目名字+应收金额”
            List<HashMap<String,Double>> chargedItemsPriceList = roomChargeMapper.findBySId(spaceInfoEntity.getId());
            StringBuilder sb=new StringBuilder();
            for (HashMap<String,Double> chargePrice: chargedItemsPriceList) {
                Set<String> keys= chargePrice.keySet();
                for (String k: keys) {
                    sb.append(chargePrice.get(k));
                }
                sb.append(";");
            }


            RoomChargeProDto roomChargeProDto=new RoomChargeProDto();
            roomChargeProDto.setRoom(houseName);
            roomChargeProDto.setChargedItemsPriceStr(sb.toString());
            System.out.println("sb.toString()="+sb.toString());
            //还需要查询业主信息
            //先通过房间id，查询它的业主id
            Long owerId= propertyServiceImpl.findOwerIdBySid(spaceInfoEntity.getId());
            //然后根据业主id，查询业主姓名
            String ownerName02=propertyServiceImpl.findOwerNameById(owerId);
            //假如前端模糊查询业主姓名：需要剔除不含“ownerName”的数据
            if (ownerName!=null && !(ownerName.equals(""))){
                if (ownerName02==null
                        || (ownerName02!=null && (!ownerName02.contains(ownerName)))) {
                   continue;
                }
            }
            roomChargeProDto.setOwnerName(ownerName02);
            roomChargeProDtoList.add(roomChargeProDto);
        }
        return roomChargeProDtoList;
    }





    /**
     * 新增 一个收费项目、房间的中间表
     * @author hejie
     * @param id:根据 房间、收费项目中间表的id：删除一个中间表的记录
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,rollbackFor = Exception.class)
    public int delRoomCharge(Long id){
        return roomChargeMapper.delRoomCharge(id);
    }

    /**
     * 新增 一个收费项目、房间的中间表
     * @author hejie
     * @param chargedItemsInfoId  收费项目外键id
     * @param currentRoomId  房间外键id：用户当前点击的房间的id
     *                       注意：impl中根据“收费项目”中的“周期单位”自己设置“开始计费时间和结束计费时间”
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,rollbackFor = Exception.class)
    public void addRoomCharge(Long currentRoomId, Long chargedItemsInfoId){
        RoomChargedItemsInfoEntity roomCharge=new RoomChargedItemsInfoEntity();

        //设置房间外键
        SpaceInfoEntity spaceInfoEntity=new SpaceInfoEntity();
        spaceInfoEntity.setId(currentRoomId);
        roomCharge.setSpaceInfoEntity(spaceInfoEntity);
        //设置收费项目外键
        ChargedItemsInfoEntity chargedItemsInfo=new ChargedItemsInfoEntity();
        chargedItemsInfo.setId(chargedItemsInfoId);
        roomCharge.setChargedItemsInfoEntity(chargedItemsInfo);


        //根据“收费项目”中的“周期单位”自己设置“开始计费时间和结束计费时间”
        //如果是周期性：结束时间是 当前时间+一个周期； 如果是“临时性”：结束时间是 当前时间,并在房间、收费中间表中添加“应缴金额”和“应交合计”为该收费项目单价
        ChargedItemsInfoEntity chargedItemsInfoEntity= chargedItemsService.findById(chargedItemsInfoId);
        //'收费方式。1--周期性，2--临时性',
        Byte chargeWay= chargedItemsInfoEntity.getChargeWay();
        //“开始计费日期”
        Date now= new Date();
        roomCharge.setBillStartDate(now);
        //1.“临时性”：计费结束时间==计费开始时间
        if (chargeWay==2){
            //“计费结束时间”
            roomCharge.setBillEndDate(now);
            //"收费项目的计费单价，作为 房间收费中间表的 应收金额、应缴合计"。 “周期性的话，应该设置定时任务，看计费结束时间到了就设置 应收金额、应缴合计；违约天数到后，开始计算并修改“房间收费中间表”违约金”
            roomCharge.setAmountReceivable(chargedItemsInfoEntity.getBilliUnitPrice());
            roomCharge.setTotalPayable(chargedItemsInfoEntity.getBilliUnitPrice());
        }
        //2.“周期性”：计费结束时间==计费开始时间 + “周期”数量个“周期单位”
        else if (chargeWay==1){
            Calendar calendar=Calendar.getInstance();
            calendar.setTime(now);
            //获取周期单位：'周期单位。1-月，2-日'
            Byte cycleUnits=chargedItemsInfoEntity.getCycleUnits();
            //周期单位是“月”
            if (cycleUnits==1){
                calendar.add(Calendar.MONTH, 1);
            }
            //周期单位是“日”
            else if (cycleUnits==2){
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
            //设置 “计费结束时间”
            roomCharge.setBillEndDate(calendar.getTime());
        }

        //新增  房间、收费项目中间表
        roomChargeMapper.addRoomCharge(roomCharge);
    }

    /**
     * 修改：房间、项目中间表
     * @param roomChargedItemsInfoEntity
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,rollbackFor = Exception.class)
    public int update(RoomChargedItemsInfoEntity roomChargedItemsInfoEntity){
        return roomChargeMapper.update(roomChargedItemsInfoEntity);
    }

    /**
     * 分页查询数据:通过房间id查询 该房间的收费项目
     *  ----还没有写完：目前查询了收费项目和 中间表的信息，房间的信息还没有查： 在impl中还要去根据 roomId去查询房间信息；然后把房间信息放到 本微服务mapper查询回来的List中（比如用set方法）
     * @author hejie
     * @param pageNum 第几页
     * @param pageSize 每页显示多少条数据
     * @param column 排序的字段
     * @param order 升序还是降序
     * @param roomId 房间的id
     * @param roomName 页面上显示的房间名字（它不去数据库参与查询，而是直接在impl中赋值），如3-5-1002（指3号楼-5栋-10层-02号）
     * @return
     */
    @Override
    public PageInfo<RoomChargeDto> findRoomChargeItemByRoomId(int pageNum, int pageSize, String column,
                                                              String order, Long roomId,String roomName){
        PageInfo<RoomChargeDto> pages= PageHelper.startPage(pageNum,pageSize).
                doSelectPageInfo(()->roomChargeMapper.findRoomChargeItemByRoomId(roomId,column,order));

        List<RoomChargeDto> roomChargeDtoList = pages.getList();
        //合计：应收、优惠、减免、预收金、押金（他们只计算一次，在前端用数组下标0来得出）
        CustomerChargeTotalDto customerChargeTotalDto=null;

        //设置房间名字，就可以不去跨库查询了：如3-5-1002（指3号楼-5栋-10层-02号）、业主、合计
        for (int i=0; i<roomChargeDtoList.size(); i++) {
            if (roomChargeDtoList!=null
                    && roomChargeDtoList.get(i)!=null){
                //页面上显示的房间名字（它不去数据库参与查询，而是直接在impl中赋值）
                roomChargeDtoList.get(i).setRoomName(roomName);

                //--调用其他微服务：根据房间id查询 房间的id、简称、全称
                SpaceInfoEntity spaceInfoEntity= projectServiceImpl.findSpaceById(roomId);
                //给楼栋单元赋值：从 全称 截取出“楼栋单元”
                String fullname= spaceInfoEntity.getFullname();
                String[] roomNameArr=fullname.split("-");
                String buildAndUnit=roomNameArr[1]+roomNameArr[2];
                roomChargeDtoList.get(i).setBuildAndUnit(buildAndUnit);
                roomChargeDtoList.get(i).setSpaceInfoEntity(spaceInfoEntity);

                //调用其他微服务：根据 房间id 查询 该房间的业主
                OwnerInfoEntity ownerInfoEntity= propertyServiceImpl.findOwerBySid(roomId);
                roomChargeDtoList.get(i).setOwnerInfoEntity(ownerInfoEntity);

                //合计：应收、优惠、减免、预收金、押金（他们只计算一次，在前端用数组下标0来得出）
                //第一次的时候赋值
                if (customerChargeTotalDto==null){
                    //先查询customerChargeTotalDto的其中3个：应收合计，优惠金额总计，减免金额总计
                    customerChargeTotalDto= roomChargeMapper.findTotalByrid(roomId);
                    //然后查询该房间的 预收金额之和、押金金额之和
                    //chargeType：收费类型是 预收金还是押金：1-押金，2-预收金
                    Byte DEPOSIT =1;//押金
                    Byte ADVANCEPAYMENT =2;//预收金
                    Double deposit=roomChargeMapper.findaDvanceDepositTotalByrid(roomId,DEPOSIT);
                    Double advancepayment=roomChargeMapper.findaDvanceDepositTotalByrid(roomId,ADVANCEPAYMENT);
                    customerChargeTotalDto.setAdvancePayTotal(advancepayment);
                    customerChargeTotalDto.setDepositTotal(deposit);

                    roomChargeDtoList.get(0).setCustomerChargeTotalDto(customerChargeTotalDto);
                }
            }

        }
        pages.setList(roomChargeDtoList);

        return pages;
        //现在不需要哦了--还需要  ----去根据 roomId去查询房间信息；然后把房间信息放到 本微服务mapper查询回来的List中（比如用set方法）
    }



    /**
     *  每天定时任务1 sql1：结束时间到了，设置“收费项目中间表”  amount_receivable 和 total_payable 设置为项目的价格：收费表、中间表 联查
     *      条件：1.计费结束时间到了，中间表amount_receivable、total_payable其中一个为0或null
     *        2.没有支付 （即r.complete_payment_status=2）
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,rollbackFor = Exception.class)
    public int updateReceivablePayable(){
        return roomChargeMapper.updateReceivablePayable();
    }

    /**
     *  每天定时任务2 sql2：
     *    1.结束时间 + 违约天数 >now()：计算违约金： 违约金率*(now-违约天数-结束时间) ：收费表、中间表 联查
     *    2.没有支付（即r.complete_payment_status=2）
     *    DATEDIFF(date1,date2)    两个日期相减函数，返回date1-date2相差的天数
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,rollbackFor = Exception.class)
    public int updateLiquidatedDamages(){
        return roomChargeMapper.updateLiquidatedDamages();
    }

}
